home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- /*
- * minorly customized for gcc lib
- * ++jrb
- * and for the sfp004 as well as the TT's 68881
- * mjr++
- * and for turbo C and the MiNT library
- * ++um,mh
- * bugfixes + ieee double extended support (new float conversion
- * routine that can cope with very large/small numbers)
- * ++bm
- */
-
- #ifndef __NO_FLOAT__
- # define __FLOATS__ 1
- #endif
-
- #ifdef LIBC_SCCS
- static char sccsid[] = "@(#)doprnt.c 5.37 (Berkeley) 3/26/89";
- #endif /* LIBC_SCCS */
-
- #include <compiler.h>
- #ifdef __TURBOC__
- #include <sys\types.h>
- #else
- #include <sys/types.h>
- #endif
- #include <stdarg.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <limits.h>
- #include <math.h> /* mjr++ */
-
- #ifdef __FLOATS__
- # include "flonum.h"
- static void cvt __PROTO((double, short, short, short, char *, short *,
- char *, short *, char *, short *, short *, char *, short *,
- short *, char *));
-
- # if defined __IEEE_DOUBLE_REAL__ /* 64 bits */
- # define NAN_HI 0x7fffffffL
- # define NAN2_HI 0xffffffffL /* the sign may be negative */
- # define NAN_LO 0xffffffffL
-
- # define INF_HI 0x7ff00000L
- # define INF_LO 0x00000000L
-
- # define MAXEXP 308 /* 11 bit exponent => 308 decimal digits */
- # define MAXEXPLEN 3 /* length of the exponent itself (00..308) */
- # define MAXFRACT 15 /* 53 bit fraction => max. 15 decimal digits */
-
- # elif defined __IEEE_DOUBLE_EXTENDED__ /* 80 bits */
- # define NAN_HI 0x7fffffffL
- # define NAN2_HI 0xffffffffL /* the sign may be negative */
- # define NAN_LO 0xffffffffL
- # define NAN_80 0xffff
-
- # define INF_HI 0x7fff0000L
- # define INF_LO 0x00000000L
- # define INF_80 0x0000
-
- # define MAXEXP 4932 /* 15 bit exponent => 4932 decimal digits */
- # define MAXEXPLEN 4 /* length of the exponent itself (00..4932) */
- # define MAXFRACT 19 /* 64 bit fraction => 19 decimal digits */
-
- # else
- # error Floating point format not specified
- # endif
- #endif /* __FLOATS__ */
-
- #ifndef __GNUC__ /* gcc lib has these typedefs in sys/types.h */
- #ifndef __MINT__ /* as does the MiNT library */
- typedef unsigned char u_char;
- typedef unsigned long u_long;
- #endif
- #endif
-
- #if defined (__M68881__) && !defined (sfp004)
- # include <math-68881.h> /* mjr: use the inline functions */
- #endif __M68881__
-
- #define DEFPREC 6
-
- #define MAXINTLEN 23 /* sufficient for 64 bits as octals + prefix 0 */
-
- #ifdef __FLOATS__
- # if MAXINTLEN > MAXFRACT
- # define BUF MAXINTLEN
- # else
- # define BUF MAXFRACT
- # endif
- # define BUF3 (MAXEXPLEN + 2)
- #else
- # define BUF MAXINTLEN
- #endif /* __FLOATS__ */
-
- #define PUTC(ch) if( fputc(ch, fp) == EOF ) return EOF;
-
- #define ARG(signtag) \
- _ulong = \
- flags&LONGINT ? \
- (unsigned long)va_arg(argp, signtag long) : \
- (flags&SHORTINT ? \
- (unsigned long)(signtag short)va_arg(argp, signtag short):\
- (unsigned long)va_arg(argp, signtag int))
-
- /* bm said:
- * shorts are always promoted to ints; thus, it's `va_arg(... int)'
- * for `flags&SHORTINT'!
- *
- * sorry dont agree, it that is the case then <stdarg.h> should take
- * care of it when we say va_arg(argp, short)
- */
-
- #define TEN_MUL(X) ((((X) << 2) + (X)) << 1)
-
- #define todigit(c) ((c) - '0')
- #define tochar(n) ((n) + '0')
-
- #define LONGINT 0x01 /* long integer */
- #define LONGDBL 0x02 /* long double; unimplemented */
- #define SHORTINT 0x04 /* short integer */
- #define ALT 0x08 /* alternate form */
- #define LADJUST 0x10 /* left adjustment */
- #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
- #define HEXPREFIX 0x40 /* add 0x or 0X prefix */
-
- #if defined(__GNUC__) && (!defined(__NO_INLINE__))
- #ifdef __M68020__
-
- #define _ICONV(NUMBER, BASE, BUF) \
- { \
- long i; \
- do \
- { \
- __asm__ volatile \
- ("divull %3,%0:%1" \
- : "=d"((long)(NUMBER)), "=d"(i) \
- : "0"((long)(NUMBER)), "d"((long)(BASE))); \
- *--(BUF) = digs[i]; \
- } \
- while (NUMBER); \
- }
-
- #else /* !__M68020 */
-
- #define _ICONV(NUMBER, BASE, BUF) \
- { \
- \
- while((NUMBER) > 65535L) \
- { \
- extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */ \
- register long i __asm ("d1"); \
- __asm__ volatile("
- movl %3,sp@-;
- movl %2,sp@-;
- jsr ___udivsi3;
- addqw #8,sp;
- movl d0,%0" \
- : "=r"((long)NUMBER), "=d"(i) \
- : "0"((long)NUMBER), "r"((long)BASE) \
- : "d0", "d1", "a0", "a1"); \
- *--BUF = digs[i]; \
- } \
- do \
- { \
- short i; \
- __asm__ volatile("
- divu %3,%2;
- swap %0;
- movw %0,%1;
- clrw %0;
- swap %0" \
- : "=d"((long)NUMBER), "=g"(i) \
- : "0"((long)NUMBER), "dm"((short)BASE)); \
- *--BUF = digs[i]; \
- } while(NUMBER); \
- }
-
- #endif /* __M68020 */
-
- #else /* !__GNUC__ */
-
- #define _ICONV(NUMBER, BASE, BUF) \
- do { \
- *--(BUF) = digs[(NUMBER) % (BASE)]; \
- (NUMBER) /= (BASE); \
- } while (NUMBER);
-
- #endif /* __GNUC__ */
-
-
- int _doprnt(fp, fmt0, argp)
- register FILE *fp;
- const char *fmt0;
- va_list argp;
- {
- register const u_char *fmt; /* format string */
- register int ch; /* character from fmt */
- register int cnt; /* return value accumulator */
- register int n; /* random handy integer */
- register char *t; /* buffer pointer */
- #ifdef __FLOATS__
- /* double _double; *//* double precision arguments %[eEfgG] */
- union double_di _dd; /* _double is #defined to be _dd later on */
- char softsign; /* temporary negative sign for floats */
- #endif __FLOATS__
- u_long _ulong; /* integer arguments %[diouxX] */
- short base; /* base for [diouxX] conversion */
- short dprec; /* decimal precision in [diouxX] */
- short fieldsz; /* field size expanded by sign, etc */
- short flags; /* flags as above */
- short prec; /* precision from format (%.3d), or -1 */
- short realsz; /* field size expanded by decimal precision */
- short size; /* size of converted field or string */
- short width; /* width from format (%8d), or 0 */
- char sign; /* sign prefix (' ', '+', '-', or \0) */
- char *digs; /* digits for [diouxX] conversion */
- char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
- #ifdef __FLOATS__
- short floatflag; /* indicates floating point conversion */
- /* output for f.p.:
- * string buf (size bytes)
- * zero1 * '0'
- * '.' if point is set
- * zero2 * '0'
- * string buf2 (size2 bytes)
- * zero3 * '0'
- * string buf3 (size3 bytes) (exponent)
- */
- short zero1;
- char point;
- short zero2;
- short size2;
- char buf2[BUF];
- short zero3;
- short size3;
- char buf3[BUF3];
- #endif
-
- t = buf;
- fmt = (const u_char *) fmt0;
- digs = "0123456789abcdef";
- for (cnt = 0;; ++fmt) {
- if ((ch = *fmt) == 0)
- return (cnt);
- if (ch != '%') {
- PUTC(ch);
- cnt++;
- continue;
- }
- #ifdef __FLOATS__
- floatflag = 0;
- #endif
- flags = 0; dprec = 0; width = 0;
- prec = -1;
- sign = '\0';
-
- rflag: switch (*++fmt) {
- case ' ':
- /*
- * ``If the space and + flags both appear, the space
- * flag will be ignored.''
- * -- ANSI X3J11
- */
- if (!sign)
- sign = ' ';
- goto rflag;
- case '#':
- flags |= ALT;
- goto rflag;
- case '*':
- /*
- * ``A negative field width argument is taken as a
- * - flag followed by a positive field width.''
- * -- ANSI X3J11
- * They don't exclude field widths read from args.
- */
- if ((width = (short)(va_arg(argp, int))) >= 0)
- goto rflag;
- width = -width;
- /* FALLTHROUGH */
- case '-':
- flags |= LADJUST;
- goto rflag;
- case '+':
- sign = '+';
- goto rflag;
- case '.':
- if (*++fmt == '*')
- n = va_arg(argp, int);
- else {
- n = 0;
- while (isascii(*fmt) && isdigit(*fmt))
- n = TEN_MUL(n) + todigit(*fmt++);
- --fmt;
- }
- prec = n < 0 ? -1 : n;
- goto rflag;
- case '0':
- /*
- * ``Note that 0 is taken as a flag, not as the
- * beginning of a field width.''
- * -- ANSI X3J11
- */
- flags |= ZEROPAD;
- goto rflag;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = 0;
- do {
- n = TEN_MUL(n) + todigit(*fmt);
- } while (isascii(*++fmt) && isdigit(*fmt));
- width = n;
- --fmt;
- goto rflag;
- case 'L':
- flags |= LONGDBL;
- goto rflag;
- case 'h':
- flags |= SHORTINT;
- goto rflag;
- case 'l':
- flags |= LONGINT;
- goto rflag;
- case 'c':
- *(t = buf) = va_arg(argp, int);
- size = 1;
- sign = '\0';
- goto pforw;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- ARG(signed);
- if ((long)_ulong < 0) {
- _ulong = -_ulong;
- sign = '-';
- }
- base = 10;
- goto number;
- #ifdef __FLOATS__
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
-
- #define _double _dd.d
- _double = va_arg(argp, double);
-
- /* mjr: check for NANs */
- if (_dd.i[0] == NAN_HI || _dd.i[0] == NAN2_HI) {
- t = buf;
- t = strcpy(t, "NaN");
- size = strlen(t);
- goto pforw;
- }
-
- if (prec == -1)
- prec = DEFPREC;
- /*
- * softsign avoids negative 0 if _double is < 0 and
- * no significant digits will be shown
- */
- if (_double < 0) {
- softsign = '-';
- _double = -_double;
- }
- else
- softsign = 0;
- /* mjr: check for +-INFINITY */
- if (((unsigned long)_dd.i[0] == INF_HI) &&
- ((unsigned long)_dd.i[1] == INF_LO)
- #ifdef __IEEE_DOUBLE_EXTENDED__
- && ((unsigned int)_dd.j[4] == INF_80)
- #endif
- ) {
- t = buf;
- if(softsign == 0)
- t = strcpy(t, "+Inf");
- else
- t = strcpy(t, "-Inf");
- size = strlen(t);
- goto pforw;
- }
- floatflag = 1;
-
- cvt(_double, prec, flags, (int) *fmt,
- &softsign, &size, buf, &zero1, &point,
- &zero2, &size2, buf2, &zero3, &size3, buf3);
- t = buf;
-
- /*
- * softsign is set to 0 by cvt if the value
- * becomes 0 by rounding
- */
- if (softsign)
- sign = '-';
- goto pforw;
- #endif /* __FLOATS__ */
- case 'n':
- if (flags & LONGINT)
- *va_arg(argp, long *) = cnt;
- else if (flags & SHORTINT)
- *va_arg(argp, short *) = cnt;
- else
- *va_arg(argp, int *) = cnt;
- break;
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- ARG(unsigned);
- base = 8;
- goto nosign;
- case 'p':
- /*
- * ``The argument shall be a pointer to void. The
- * value of the pointer is converted to a sequence
- * of printable characters, in an implementation-
- * defined manner.''
- * -- ANSI X3J11
- */
- /* NOSTRICT */
- _ulong = (u_long)va_arg(argp, void *);
- base = 16;
- goto nosign;
- case 's':
- if ((t = va_arg(argp, char *)) == 0)
- t = "(null)";
- if (prec >= 0) {
- /*
- * can't use strlen; can only look for the
- * NUL in the first `prec' characters, and
- * strlen() will go further.
- */
- #ifdef __STDC__
- char *p;
- void *memchr(const void *, int, size_t);
- #else
- char *p, *memchr();
- #endif
-
- if ((p = (char *)memchr(t, 0, (size_t)prec))
- != NULL) {
- size = p - t;
- if (size > prec)
- size = prec;
- } else
- size = prec;
- } else
- size = (int)strlen(t);
- sign = '\0';
- goto pforw;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- ARG(unsigned);
- base = 10;
- goto nosign;
- case 'X':
- digs = "0123456789ABCDEF";
- /* FALLTHROUGH */
- case 'x':
- ARG(unsigned);
- base = 16;
- /* leading 0x/X only if non-zero */
- if (flags & ALT && _ulong != 0)
- flags |= HEXPREFIX;
-
- /* unsigned conversions */
- nosign: sign = '\0';
- /*
- * ``... diouXx conversions ... if a precision is
- * specified, the 0 flag will be ignored.''
- * -- ANSI X3J11
- */
- number: if ((dprec = prec) >= 0)
- flags &= ~ZEROPAD;
-
- /*
- * ``The result of converting a zero value with an
- * explicit precision of zero is no characters.''
- * -- ANSI X3J11
- */
- t = buf + BUF;
- if (_ulong != 0 || prec != 0) {
- _ICONV(_ulong, base, t);
- digs = "0123456789abcdef";
- if (flags & ALT && base == 8 && *t != '0')
- *--t = '0'; /* octal leading 0 */
- }
- size = buf + BUF - t;
-
- pforw:
- /*
- * All reasonable formats wind up here. At this point,
- * `t' points to a string which (if not flags&LADJUST)
- * should be padded out to `width' places. If
- * flags&ZEROPAD, it should first be prefixed by any
- * sign or other prefix; otherwise, it should be blank
- * padded before the prefix is emitted. After any
- * left-hand padding and prefixing, emit zeroes
- * required by a decimal [diouxX] precision, then print
- * the string proper. For floating values: This string
- * is followed by '0's, the decimal point if required,
- * again '0's, a second string, once more '0's and a
- * third string (the exponent). Finally, if LADJUST,
- * pad with blanks.
- */
-
- /*
- * compute actual size, so we know how much to pad
- * fieldsz excludes decimal prec; realsz includes it
- */
- #ifdef __FLOATS__
- if (floatflag != 0)
- fieldsz = size + zero1 + (point != 0)
- + zero2 + size2 + zero3 + size3;
- else
- #endif
- fieldsz = size;
- if (sign)
- fieldsz++;
- if (flags & HEXPREFIX)
- fieldsz += 2;
- realsz = dprec > fieldsz ? dprec : fieldsz;
-
- /* right-adjusting blank padding */
- if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
- for (n = realsz; n < width; n++)
- PUTC(' ');
- /* prefix */
- if (sign)
- PUTC(sign);
- if (flags & HEXPREFIX) {
- PUTC('0');
- PUTC((char)*fmt);
- }
- /* right-adjusting zero padding */
- if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
- for (n = realsz; n < width; n++)
- PUTC('0');
- /* leading zeroes from decimal precision */
- for (n = fieldsz; n < dprec; n++)
- PUTC('0');
-
- /* the string or number proper */
- for (n = size; --n >= 0; )
- PUTC(*t++);
- #ifdef __FLOATS__
- if (floatflag != 0) {
- while (--zero1 >= 0)
- PUTC('0');
- if (point != 0)
- PUTC('.');
- while (--zero2 >= 0)
- PUTC('0');
- t = buf2;
- while (--size2 >= 0)
- PUTC(*t++);
- while (--zero3 >= 0)
- PUTC('0');
- t = buf3;
- while (--size3 >= 0)
- PUTC(*t++);
- }
- #endif /* __FLOATS__ */
- /* left-adjusting padding (always blank) */
- if (flags & LADJUST)
- for (n = realsz; n < width; n++)
- PUTC(' ');
- /* finally, adjust cnt */
- cnt += width > realsz ? width : realsz;
- break;
- case '\0': /* "%?" prints ?, unless ? is NULL */
- return (cnt);
- default:
- PUTC((char)*fmt);
- cnt++;
- }
- }
- /* NOTREACHED */
- }
-
- #ifdef __FLOATS__
-
- static int double2decimal __PROTO((double, char *, char *));
-
- void cvt(number, prec, flags, fmtch,
- sign, size1, output1, zero1, point, zero2,
- size2, output2, zero3, size3, output3)
- double number;
- short prec, flags, fmtch;
- char *sign, *point;
- short *zero1, *zero2, *zero3;
- short *size1, *size2, *size3;
- char *output1, *output2, *output3;
- {
- /* new floating point conversion routine, ++bm
- *
- * The output consists of several parts that _doprnt has to
- * put together:
- * - *sign (it is set to '\0' if the number becomes 0 by rounding)
- * - string output1 with length *size1
- * - *zero1 '0's
- * - *point (it is set to '\0' or '.')
- * - *zero2 '0's
- * - string output2 with length *size2
- * - *zero3 '0's
- * - string output3 with length *size3
- */
-
- /* additional bytes: 1 at the beginning,
- * 1 at the end (for rounding) */
- #define MANTLEN (MAXFRACT + 2)
- char mantstr[MANTLEN];
- char *mant;
- short exp10;
- short roundprec;
-
- exp10 = (short) double2decimal(number, mantstr, mantstr + MANTLEN);
-
- /* mantstr should start with '0', example: if number was 1234.0,
- * manstr is "0123400"... and exp10 is 3
- */
-
- /* make roundprec the number of significant digits we need */
- switch (fmtch) {
- case 'f':
- /* prec is the number of fraction digits */
- roundprec = (exp10 + 1) + prec;
- if (roundprec < 0)
- /*
- * f.p. value is too small,
- * no significant digits
- */
- roundprec = 0;
- break;
-
- case 'g':
- case 'G':
- /* prec is the number of significant digits */
- if (prec == 0) prec++;
- roundprec = prec;
- break;
-
- case 'e':
- case 'E':
- /* prec is the number of fraction digits in d.dddEdd */
- roundprec = prec + 1;
- }
- if (roundprec > MAXFRACT)
- roundprec = MAXFRACT;
-
- /* now round */
- {
- char *tmp = mantstr + roundprec + 1;
- /* tmp points to a digit that we don't need */
- if (*tmp >= '5') {
- do {
- /* necessary if a '9' was incremented */
- *tmp = '0';
- (*--tmp)++;
- } while (*tmp > '9');
- }
- }
-
- if (mantstr[0] > '0') {
- /* one more digit because of rounding */
- if (roundprec == 0) { /* only possible for %f */
- if (exp10 + 1 + prec == 0) {
- /* see above: roundprec = ... */
- roundprec++;
- mant = mantstr;
- exp10++;
- }
- else {
- /* the number is too small */
- *sign = '\0';
- exp10 = 0;
- }
- }
- else {
- mant = mantstr;
- exp10++;
- }
- }
- else {
- /* maybe there's nothing left now? */
- char *tmp;
- for (tmp = mantstr + roundprec; *tmp == '0'; tmp--) {
- if (tmp == mantstr) {
- /* after rounding, 0.0 is left */
- *sign = '\0';
- roundprec = 0;
- /* the string of digits is not needed */
- exp10 = 0;
- break;
- }
- }
- mant = mantstr + 1; /* the leading '0' is not needed */
- }
-
- /* now mant points to a string of roundprec digits */
-
- if (fmtch == 'g' || fmtch == 'G') {
- short significdig = prec;
-
- if (!(flags & ALT)) {
- /* cut off trailing zeros */
- char *tmp;
-
- /*
- * if the f.p. is 0.0, roundprec == 0,
- * so loop isn't executed
- */
- for (tmp = mant+roundprec-1;
- tmp >= mant && *tmp == '0'; tmp--)
- roundprec--;
- significdig = roundprec;
- /*
- * before, significdig was the max. number
- * of significant digits, now it's the actual number
- */
- }
-
- if (exp10 >= -4 && exp10 < prec || roundprec == 0) {
- /* format is like %f */
-
- /*
- * significdig is the number of significant digits,
- * %f prints prec fraction digits
- *
- * if exp10>=0, (exp10+1) is the number of digits on
- * the left side of the decimal point;
- * if exp10<0, -(exp10+1) is the number of zeros on
- * the right side of the dec.point
- */
- prec = significdig - exp10 - 1;
- if (prec < 0)
- /* zeros on the left side of the dec.point? */
- prec = 0;
- fmtch = 'f'; /* continue as if it was %f */
- }
- else {
- /* format is like %[eE] */
-
- /*
- * significdig is the number of significant digits,
- * for %[eE], it's the number
- * of fraction digits in 1.234E3
- */
- prec = significdig - 1;
- /*
- * prec was > 0 before:
- * it could only be 0 if the f.p. value was 0.0,
- * and then exp10 would be 0 and this wouldn't be
- * executed
- */
- fmtch -= 2;
- /* continue as if it was %[eE] (g -> e, G -> E) */
- }
- } /* end of %[gG] */
-
- /* %[eEf] remains */
- /* now distribute the number of digits and zeros to the fields */
- if (fmtch == 'f') {
- *size1 = exp10 + 1;
- if (*size1 > roundprec)
- *size1 = roundprec;
- else if (*size1 < 0)
- *size1 = 0;
-
- *zero1 = *size1 ?
- exp10 + 1 - roundprec
- : 1;
- if (*zero1 < 0)
- *zero1 = 0;
- *point = (flags & ALT) || prec > 0 ? '.' : '\0';
- *zero2 = -exp10 - 1;
- if (*zero2 < 0)
- *zero2 = 0;
- *size2 = roundprec - *size1;
- *zero3 = prec - *zero2 - *size2;
- *size3 = 0; /* no exponent */
- } /* end of %f */
- else {
- /* it's %[eE] */
- if (roundprec == 0) {
- /* f.p. value is 0 */
- *size1 = 0;
- *zero1 = 1;
- }
- else {
- *size1 = 1;
- *zero1 = 0;
- }
- *point = (flags & ALT) || prec > 0 ? '.' : '\0';
- *zero2 = 0;
- *size2 = roundprec - *size1;
- *zero3 = prec - *size2;
-
- /* we need the exponent */
- *output3++ = fmtch; /* 'e' or 'E' */
- if (exp10 >= 0)
- *output3++ = '+';
- else {
- *output3++ = '-';
- exp10 = -exp10;
- }
- *size3 = 2;
- {
- char tmp[MAXEXPLEN];
- char *p = tmp;
-
- /* convert exponent to digits, but reversed */
- *p++ = tochar(exp10 % 10); /* at least 2 digits */
- exp10 /= 10;
- do {
- *p++ = tochar(exp10 % 10);
- exp10 /= 10;
- } while (exp10 > 0);
-
- /* reverse exponent */
- do {
- *output3++ = *--p;
- ++*size3;
- } while (p > tmp);
- }
- } /* end of %[eE] */
-
- /* distribute digits to output fields */
- {
- short n;
-
- for (n = 0; n < *size1; n++)
- *output1++ = *mant++;
- for (n = 0; n < *size2; n++)
- *output2++ = *mant++;
- }
- } /* end of function cvt */
-
- static int
- double2decimal(number, mant, endmant)
- double number;
- char *mant, *endmant;
- {
- /*
- * Convert `number' to decimal (exponent is returned)
- * number must be positive!
- * The string `mant' has the length endmant - mant.
- *
- * Example: If number == 1.23e4, mant will be set to "0123000"..
- * (implicit decimal point after the second character)
- * and 4 will be returned.
- */
- int exp2, exp10;
- double intpart, fractpart;
-
- frexp(number, &exp2);
- /* number == (0.5 .. 1.0) * 2^exp2 */
- {
- short tmp, t;
-
- tmp = (int) ((long) exp2 * 30103L / 100000L);
- /* tmp == exp2 * log 2 */
- t = tmp;
-
- #if MAXEXP >= 1000
- while (tmp > +1000)
- {tmp -= 1000; number *= 1.0e-1000;}
- while (tmp < -1000)
- {tmp += 1000; number *= 1.0e+1000;}
- #endif
- while (tmp > +100)
- {tmp -= 100; number *= 1.0e-100;}
- while (tmp < -100)
- {tmp += 100; number *= 1.0e+100;}
- while (tmp > +10)
- {tmp -= 10; number *= 1.0e-10;}
- while (tmp < -10)
- {tmp += 10; number *= 1.0e+10;}
-
- exp10 = t - tmp;
- }
- /*
- * what was the argument number before is now (number * 10^exp10)
- *
- * now make sure that 1 <= number < 10
- */
-
- while (number >= 10.0)
- {exp10++; number /= 10.0;}
- while ((fractpart = modf(number, &intpart)) != 0.0 && intpart == 0.0)
- {exp10--; number *= 10.0;}
-
- /* intpart is now the integer part of number (1..9 or 0) */
- /* number == intpart + fractpart */
-
- *mant++ = tochar(((int) intpart) / 10); /* should be '0' */
- *mant++ = tochar(((int) intpart) % 10);
- for ( ; mant < endmant; mant++) {
- fractpart = modf(10.0 * fractpart, &intpart);
- *mant = tochar((int) intpart);
- }
-
- return exp10;
- }
- #endif __FLOATS__
-